package com.baosight.xCyber;

import com.baosight.xCyber.model.TagNode;

import java.util.*;
import java.util.logging.Logger;

/**
 * 建立字典树的算法，并遍历字典树找出父节点名称
 *
 * @author 吴起航
 */
public class BuilderTree {

    public static Map<String, TagNode> tagNodeMap = new HashMap<>();
    private static Map<String, TagNode> codeMapTemp;
    private static Logger log = Logger.getLogger(BuilderTree.class.getSimpleName());
    //用于储存所有的叶子节点上的数据
    public static List<TagNode> data = new ArrayList<>();
    /**
     * 初始化根节点
     */
    private static TrieNode root = new TrieNode();

    private static class TrieNode {
        TrieNode preNode = null;    //获取父节点
        boolean isEnd = true;  //尾字符标识
        int deep = 0;       //做hash使用，当出现相同字符时，用于定位指定字符
        char content = 0;   //当前节点的字符
        boolean childFlag = true; //标识树的末端
        LinkedList<TrieNode> child = new LinkedList<>();//获取子节点

        TrieNode() {
        }

        TrieNode(char content) {
            this.content = content;
            this.isEnd = false;
        }

        public LinkedList<TrieNode> getChild() {
            return child;
        }

        public void setChild(LinkedList<TrieNode> child) {
            this.child = child;
        }

        void setPreNode(TrieNode node) {
            preNode = node;
        }

        TrieNode getPreNode() {
            return preNode;
        }


        /**
         * child中是否有此Node
         *
         * @param character 保存的char
         * @return 存在返回不存在返回Null
         */
        TrieNode getNode(Character character) {
            for (TrieNode aChild : child) {
                if (aChild.content == character) {
                    return aChild;
                }
            }
            return null;
        }

        @Override
        public boolean equals(Object o) {
            TrieNode trieNode = (TrieNode) o;
            return content == trieNode.content;
        }

        @Override
        public int hashCode() {
            return Objects.hash(preNode, isEnd, deep, content, child);
        }
    }

    /**
     * 用字典表map建立字典树
     */
    public static Map<String, TagNode> initMap(Map<String, TagNode> codeMap, List<TagNode> dataList) {
        codeMapTemp = codeMap;
        BuilderTree tree = new BuilderTree();
        //判断树是否已经初始化
        if(root.childFlag){
            for (Map.Entry<String, TagNode> entry : codeMap.entrySet()) {
                TagNode tagNode = entry.getValue();
                tree.buildTrieTree(tagNode);
            }
        }
        log.info("字典树建立完毕");

        for (TagNode tagNode : dataList) {
            tree.addTagNode(tagNode);
        }
        log.info("获得目标树结构");

        return tree.returnMap();
    }


    /**
     * 建立字典树的算法，并遍历字典树找出父节点名称
     *
     * @param tagNode 需要解析的节点
     */
    public void buildTrieTree(TagNode tagNode) {
        int deep = 0;
        String tagName = tagNode.tagName;

        //初始化根节点
        TrieNode currNode = root;
        while (deep < tagName.length()) {
            /* 判断当前node的child，如果为空直接添加，不为空，
             * 查找是否含有，不含有则新建并设为currNode，含有则找到并设置为currNode
             */
            char c = tagName.charAt(deep);
            TrieNode node = currNode.getNode(c);
            //判断当前字符是否在其子节点字符中
            if (node != null) {
                //若是，则设置下次循环的主节点为当前字符
                currNode = node;
            } else {
                //对于字典表数据，若不是，则新建节点：设置其父节点为根节点,并添加至根节点的子节点
                //深度+1
                //设置下次循环的主节点为当前字符
                node = new TrieNode(c);
                node.setPreNode(currNode);
                node.deep = deep + 1;
                node.childFlag = true;
                currNode.childFlag = false;
                currNode.child.add(node);
                currNode = node;
            }

            //判断当前字符是否已经遍历完毕
            //同时添加至map集合中
            if (deep == tagName.length() - 1) {
                currNode.isEnd = true;
            }
            deep++;
        }
    }

    public void addTagNode(TagNode tagNode) {
        TrieNode currNode = root;
        int deep = 0;
        String tagName = tagNode.tagName;
        while (deep < tagName.length()) {
            char c = tagName.charAt(deep);
            TrieNode node = currNode.getNode(c);
            //判断当前字符是否在其子节点字符中
            if (node != null) {
                //若是，则设置下次循环的主节点为当前字符
                currNode = node;
                if (node.childFlag) {
                    //遍历到树的末梢
                    String parentNodeName = null;
                    if(tagNode.parentId!=null){
                        parentNodeName = tagNode.parentId;
                    }else{
                        parentNodeName = tagName.substring(0, deep + 1);
                    }
                    TagNode parentNode = codeMapTemp.get(parentNodeName);
                    tagNode.parentId = parentNodeName;

                    tagNode.setItems(null);
                    tagNode.setItemFlag(false);
                    List<TagNode> temp = parentNode.getItems();
                    temp.add(tagNode);
                    parentNode.setItems(temp);
                    data.add(tagNode);

                    //直接存放对象
                    tagNodeMap.put(parentNodeName, parentNode);
                    node = node.preNode;
                    tagNode = parentNode;
                    while(tagNode.parentId == null && tagNode.tagName != ""){
                        if(node.isEnd){
                            parentNodeName = tagName.substring(0, deep);
                            //从字典map中取得父tagNode
                            parentNode = codeMapTemp.get(parentNodeName);
                            tagNode.parentId = parentNodeName;
                            List<TagNode> childs = parentNode.getItems();
                            if (!childs.contains(tagNode)) {
                                childs.add(tagNode);
                                parentNode.setItems(childs);
                            }
                            tagNode = parentNode;
                        }
                        node = node.preNode;
                        deep--;
                    }
//                    if (parentNode.parentId == null) {
//                        tagNode = parentNode;
//                        for (int i = deep; i >= 0; i--) {
//                            node = node.preNode;
//                            if (node.isEnd) {
//                                String parentTagName = tagName.substring(0, i);
//                                //从字典map中取得父tagNode
//                                TagNode parentTagNode = codeMapTemp.get(parentTagName);
//                                tagNode.parentId = parentTagName;
//                                List<TagNode> childs = parentTagNode.getItems();
//                                if (!childs.contains(tagNode)) {
//                                    childs.add(tagNode);
//                                    parentTagNode.setItems(childs);
//                                }
//                                tagNode = parentTagNode;
//
//                            }
//                        }
//                    }
                    break;
                }
            } else {
                node = currNode;
                //在当前node的子节点下未找的该节点，保留符合父节点不符合根节点的数据
                if (node.content != 0) {
                    while (!node.isEnd) {
                        node = node.preNode;
                        deep--;
                    }
                    String parentTagName = tagName.substring(0, deep);
                    TagNode parentTag = codeMapTemp.get(parentTagName);
                    //判断otherTag有没有初始化
                    if (parentTag.otherTag == null) {
                        TagNode otherTag = new TagNode();
                        parentTag.otherTag = otherTag;
                        otherTag.tagName = "other";
                        otherTag.showName = "其他";
                        otherTag.parentId = parentTag.tagName;
                        parentTag.getItems().add(otherTag);
                    }
                    TagNode otherTag = parentTag.otherTag;

                    tagNode.parentId = otherTag.tagName;
                    tagNode.setItems(null);
                    tagNode.setItemFlag(false);
                    otherTag.getItems().add(tagNode);
                    data.add(tagNode);
                    node = node.preNode;
                    deep--;
                    tagNode = parentTag;
                    while (tagNode.parentId == null && tagNode.tagName != "") {
                        if (node.isEnd) {
                            parentTagName = tagName.substring(0, deep);
                            parentTag = codeMapTemp.get(parentTagName);
                            tagNode.parentId = parentTagName;
                            List<TagNode> childs = parentTag.getItems();
                            if (!childs.contains(tagNode)) {
                                childs.add(tagNode);
                                parentTag.setItems(childs);
                            }
                            tagNode = parentTag;
                        }
                        node = node.preNode;
                        deep--;
                    }
                }
                break;
            }
            deep++;
        }
    }


    public Map<String, TagNode> returnMap() {
        //保存完整的树节点结构
        tagNodeMap.put("root", codeMapTemp.get(""));
        return tagNodeMap;
        //分别保存树结构+叶子节点结构

    }


}
